package com.king.handler;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.king.bean.entity.*;
import com.king.bean.msg.*;
import com.king.config.GlobalConst;
import com.king.utils.BaiduAip;
import com.king.utils.StringUtils;
import com.king.utils.iRobot;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 微信普通消息处理类
 */
public class WxMessageHandler {

    /**
     * 接收并回复消息
     *
     * 当普通微信用户向公众账号发消息时，微信服务器将POST消息的XML数据包到开发者填写的URL上
     *
     * 当用户发送消息给公众号时（或某些特定的用户操作引发的事件推送时），会产生一个POST请求，
     * 开发者可以在响应包（Get）中返回特定XML结构，来对该消息进行响应（现支持回复文本、图片、图文、语音、视频、音乐）。
     * 严格来说，发送被动响应消息其实并不是一种接口，而是对微信服务器发过来消息的一次回复。
     *
     * 微信服务器在将用户的消息发给公众号的开发者服务器地址（开发者中心处配置）后，
     * 微信服务器在五秒内收不到响应会断掉连接，并且重新发起请求，总共重试三次，
     * 如果在调试中，发现用户无法收到响应的消息，可以检查是否消息处理超时。
     * 关于重试的消息排重，有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。
     *
     * 假如服务器无法保证在五秒内处理并回复，必须做出下述回复，
     * 这样微信服务器才不会对此作任何处理，并且不会发起重试（这种情况下，可以使用客服消息接口进行异步回复），
     * 否则，将出现严重的错误提示。详见下面说明：
     * 1、直接回复success（推荐方式）
     * 2、直接回复空串（指字节长度为0的空字符串，而不是XML结构体中content字段的内容为空）
     *
     * 一旦遇到以下情况，微信都会在公众号会话中，向用户下发系统提示“该公众号暂时无法提供服务，请稍后再试”：
     * 1、开发者在5秒内未回复任何内容
     * 2、开发者回复了异常数据，比如JSON数据等
     *
     * 另外，请注意，回复图片（不支持gif动图）等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器，
     * 可以使用素材管理中的临时素材，也可以使用永久素材。
     *
     * @param requestMap
     * @return
     */
    public static WxBaseMessage handleMessage(Map<String, Object> requestMap) {
        String msgType = requestMap.get("MsgType").toString();
        switch (msgType) {

            //region 接收普通消息
            case "text":
                return handleTextMessage(requestMap);

            case "image":
                System.out.println(requestMap);
                return handleImageMessage(requestMap);

            case "voice":
                return handleVoiceMessage(requestMap);

            case "video":
                return handleVideoMessage(requestMap);

            case "shortvideo":
               return handleShortVideoMessage(requestMap);

            case "link":
                return handleLinkMessage(requestMap);

            case "location":
                return handleLocationMessage(requestMap);

            case "music":
                return handleMusicMessage(requestMap);

            case "news":
                return handleNewsMessage(requestMap);
            //endregion

            //region 接收事件推送
            case "event":
                return handleEventMessage(requestMap);
            //endregion
        }

        return null;
    }

    //region 接收普通消息及被动回复消息

    /**
     * 接收并回复文本消息
     * 1.接收文本普通消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1348831860</CreateTime>
     *   <MsgType><![CDATA[text]]></MsgType>
     *   <Content><![CDATA[this is a test]]></Content>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，文本为text
     * Content	文本消息内容
     * MsgId	消息id，64位整型
     * 2.被动回复文本消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[text]]></MsgType>
     *   <Content><![CDATA[你好]]></Content>
     * </xml>
     * 参数	是否必须	描述
     * ToUserName	是	接收方帐号（收到的OpenID）
     * FromUserName	是	开发者微信号
     * CreateTime	是	消息创建时间 （整型）
     * MsgType	是	消息类型，文本为text
     * Content	是	回复的消息内容（换行：在content中能够换行，微信客户端就支持换行显示）
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleTextMessage(Map<String, Object> requestMap) {
        String content = requestMap.get("Content").toString();

        if (content.equalsIgnoreCase("图文")) {
            List<Article> articles = new ArrayList<Article>();
            articles.add(new Article("图文消息测试", "这是一则图文消息，请查收", "http://mmbiz.qpic.cn/mmbiz_jpg/vrjjk8icCmwtZOF02O3icccCXHYV3IEd16LAMZgmUsbRicZceEeQO7b06fv9ibqiaWniaweLDPlhLkNGcInGMjMdJFEA/0", "https://baidu.com"));
            WxNewsMessage news = new WxNewsMessage(requestMap, articles);
            return news;
        }

        String receiveMsg = iRobot.getRequest1(requestMap.get("Content").toString());
        if (content.contains("链接")) {
            if (content.contains("文字链接")) {
                receiveMsg += "\r\n" + "<a href=\"https://www.baidu.com\">百度一下</a>";
            } else {
                receiveMsg += "\r\n" + "https://m.baidu.com";
            }
        }

        return new WxTextMessage(requestMap, receiveMsg);
    }

    /**
     * 接收并回复图片消息
     * 1.接收图片普通消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1348831860</CreateTime>
     *   <MsgType><![CDATA[image]]></MsgType>
     *   <PicUrl><![CDATA[this is a url]]></PicUrl>
     *   <MediaId><![CDATA[media_id]]></MediaId>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，图片为image
     * PicUrl	图片链接（由系统生成）
     * MediaId	图片消息媒体id，可以调用获取临时素材接口拉取数据。
     * MsgId	消息id，64位整型
     * 2.被动回复图片消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[image]]></MsgType>
     *   <Image>
     *     <MediaId><![CDATA[media_id]]></MediaId>
     *   </Image>
     * </xml>
     * 参数	是否必须	说明
     * ToUserName	是	接收方帐号（收到的OpenID）
     * FromUserName	是	开发者微信号
     * CreateTime	是	消息创建时间 （整型）
     * MsgType	是	消息类型，图片为image
     * MediaId	是	通过素材管理中的接口上传多媒体文件，得到的id。
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleImageMessage(Map<String, Object> requestMap) {
//        return new WxImageMessage(requestMap, new Image(requestMap.get("MediaId").toString()));
        String msg = "未识别到图片文字结果";
        try {
            msg = BaiduAip.getStrByImageUrl(requestMap.get("PicUrl").toString());
//            System.out.println("百度识别结果： "+msg);
            JsonObject object = GlobalConst.gson.fromJson(msg, JsonObject.class);
            JsonArray array = object.get("words_result").getAsJsonArray();
            StringBuilder sb = new StringBuilder();
            for (JsonElement ele:array) {
                String words = ele.getAsJsonObject().get("words").getAsString();
                sb.append(words+"\r\n");
            }

            msg = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new WxTextMessage(requestMap, msg);
    }

    /**
     * 接收并回复语音消息
     * 1.1接收语音普通消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1357290913</CreateTime>
     *   <MsgType><![CDATA[voice]]></MsgType>
     *   <MediaId><![CDATA[media_id]]></MediaId>
     *   <Format><![CDATA[Format]]></Format>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	语音为voice
     * MediaId	语音消息媒体id，可以调用获取临时素材接口拉取数据。
     * Format	语音格式，如amr，speex等
     * MsgId	消息id，64位整型
     * 1.2接收开通语音识别普通消息格式
     * <xml>
     *   <ToUserName>< ![CDATA[toUser] ]></ToUserName>
     *   <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
     *   <CreateTime>1357290913</CreateTime>
     *   <MsgType>< ![CDATA[voice] ]></MsgType>
     *   <MediaId>< ![CDATA[media_id] ]></MediaId>
     *   <Format>< ![CDATA[Format] ]></Format>
     *   <Recognition>< ![CDATA[腾讯微信团队] ]></Recognition>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	语音为voice
     * MediaID	语音消息媒体id，可以调用获取临时素材接口拉取该媒体
     * Format	语音格式：amr
     * Recognition	语音识别结果，UTF8编码
     * MsgId	消息id，64位整型
     * 2.被动回复语音消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[voice]]></MsgType>
     *   <Voice>
     *     <MediaId><![CDATA[media_id]]></MediaId>
     *   </Voice>
     * </xml>
     * 参数	是否必须	说明
     * ToUserName	是	接收方帐号（收到的OpenID）
     * FromUserName	是	开发者微信号
     * CreateTime	是	消息创建时间戳 （整型）
     * MsgType	是	消息类型，语音为voice
     * MediaId	是	通过素材管理中的接口上传多媒体文件，得到的id
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleVoiceMessage(Map<String, Object> requestMap) {
        return new WxVoiceMessage(requestMap, new Voice(requestMap.get("MediaId").toString()));
    }

    /**
     * 接收并回复视频消息
     * 1.接收视频普通消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1357290913</CreateTime>
     *   <MsgType><![CDATA[video]]></MsgType>
     *   <MediaId><![CDATA[media_id]]></MediaId>
     *   <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	视频为video
     * MediaId	视频消息媒体id，可以调用获取临时素材接口拉取数据。
     * ThumbMediaId	视频消息缩略图的媒体id，可以调用多媒体文件下载接口拉取数据。
     * MsgId	消息id，64位整型
     * 2.被动回复视频消息格式；
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[video]]></MsgType>
     *   <Video>
     *     <MediaId><![CDATA[media_id]]></MediaId>
     *     <Title><![CDATA[title]]></Title>
     *     <Description><![CDATA[description]]></Description>
     *   </Video>
     * </xml>
     * 参数	是否必须	说明
     * ToUserName	是	接收方帐号（收到的OpenID）
     * FromUserName	是	开发者微信号
     * CreateTime	是	消息创建时间 （整型）
     * MsgType	是	消息类型，视频为video
     * MediaId	是	通过素材管理中的接口上传多媒体文件，得到的id
     * Title	否	视频消息的标题
     * Description	否	视频消息的描述
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleVideoMessage(Map<String, Object> requestMap) {
        return new WxVideoMessage(requestMap, new Video(requestMap.get("MediaId").toString(), "Test", "This is a test!"));
    }

    /**
     * 接收并回复小视频消息
     * 1.接收小视频普通消息
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1357290913</CreateTime>
     *   <MsgType><![CDATA[shortvideo]]></MsgType>
     *   <MediaId><![CDATA[media_id]]></MediaId>
     *   <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	小视频为shortvideo
     * MediaId	视频消息媒体id，可以调用获取临时素材接口拉取数据。
     * ThumbMediaId	视频消息缩略图的媒体id，可以调用获取临时素材接口拉取数据。
     * MsgId	消息id，64位整型
     * 2.
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleShortVideoMessage(Map<String, Object> requestMap) {
        System.out.println("handleShortVideoMessage...");
        return null;
    }

    /**
     * 接收并回复地理位置消息
     * 1.接收地理位置普通消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1351776360</CreateTime>
     *   <MsgType><![CDATA[location]]></MsgType>
     *   <Location_X>23.134521</Location_X>
     *   <Location_Y>113.358803</Location_Y>
     *   <Scale>20</Scale>
     *   <Label><![CDATA[位置信息]]></Label>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，地理位置为location
     * Location_X	地理位置维度
     * Location_Y	地理位置经度
     * Scale	地图缩放大小
     * Label	地理位置信息
     * MsgId	消息id，64位整型
     * 2.
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleLocationMessage(Map<String, Object> requestMap) {
        System.out.println("handleLocationMessage...");
        return null;
    }

    /**
     * 接收并回复链接消息
     * 1.接收链接普通消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>1351776360</CreateTime>
     *   <MsgType><![CDATA[link]]></MsgType>
     *   <Title><![CDATA[公众平台官网链接]]></Title>
     *   <Description><![CDATA[公众平台官网链接]]></Description>
     *   <Url><![CDATA[url]]></Url>
     *   <MsgId>1234567890123456</MsgId>
     * </xml>
     * 参数	描述
     * ToUserName	接收方微信号
     * FromUserName	发送方微信号，若为普通用户，则是一个OpenID
     * CreateTime	消息创建时间
     * MsgType	消息类型，链接为link
     * Title	消息标题
     * Description	消息描述
     * Url	消息链接
     * MsgId	消息id，64位整型
     * 2.
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleLinkMessage(Map<String, Object> requestMap) {
        System.out.println("handleLinkMessage...");
        return null;
    }

    /**
     * 接收并回复音乐消息
     * 1.
     * 2.被动回复音乐消息格式：
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[music]]></MsgType>
     *   <Music>
     *     <Title><![CDATA[TITLE]]></Title>
     *     <Description><![CDATA[DESCRIPTION]]></Description>
     *     <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
     *     <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
     *     <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
     *   </Music>
     * </xml>
     * 参数	是否必须	说明
     * ToUserName	是	接收方帐号（收到的OpenID）
     * FromUserName	是	开发者微信号
     * CreateTime	是	消息创建时间 （整型）
     * MsgType	是	消息类型，音乐为music
     * Title	否	音乐标题
     * Description	否	音乐描述
     * MusicURL	否	音乐链接
     * HQMusicUrl	否	高质量音乐链接，WIFI环境优先使用该链接播放音乐
     * ThumbMediaId	是	缩略图的媒体id，通过素材管理中的接口上传多媒体文件，得到的id
     * @param requestMap
     * @return
     */
    private static WxMusicMessage handleMusicMessage(Map<String, Object> requestMap) {
        return new WxMusicMessage(requestMap, new Music("Test", "this is a test", "", "", "1234567890"));
    }

    /**
     * 接收并回复图文消息
     * 1.
     * 2.被动回复图文消息格式
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[news]]></MsgType>
     *   <ArticleCount>1</ArticleCount>
     *   <Articles>
     *     <item>
     *       <Title><![CDATA[title1]]></Title>
     *       <Description><![CDATA[description1]]></Description>
     *       <PicUrl><![CDATA[picurl]]></PicUrl>
     *       <Url><![CDATA[url]]></Url>
     *     </item>
     *   </Articles>
     * </xml>
     * 参数	是否必须	说明
     * ToUserName	是	接收方帐号（收到的OpenID）
     * FromUserName	是	开发者微信号
     * CreateTime	是	消息创建时间 （整型）
     * MsgType	是	消息类型，图文为news
     * ArticleCount	是	图文消息个数；当用户发送文本、图片、语音、视频、图文、地理位置这六种消息时，开发者只能回复1条图文消息；其余场景最多可回复8条图文消息
     * Articles	是	图文消息信息，注意，如果图文数超过限制，则将只发限制内的条数
     * Title	是	图文消息标题
     * Description	是	图文消息描述
     * PicUrl	是	图片链接，支持JPG、PNG格式，较好的效果为大图360*200，小图200*200
     * Url	是	点击图文消息跳转链接
     * @param requestMap
     * @return
     */
    private static WxNewsMessage handleNewsMessage(Map<String, Object> requestMap) {
        ArrayList list = new ArrayList<Article>();
        list.add(new Article("TEST", "This is a test!", "", ""));
        return new WxNewsMessage(requestMap, list);
    }

    //endregion

    //region 接收并处理event事件推送
    /**
     * 接收并处理event事件推送
     * 用户点击自定义菜单后，微信会把点击事件推送给开发者，
     * 请注意，点击菜单弹出子菜单，不会产生上报
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleEventMessage(Map<String, Object> requestMap) {
        String event = requestMap.get("Event").toString();
        switch (event){

            //region 接收自定义菜单事件推送
            case "CLICK":
                return handleClickEventMessage(requestMap);

            case "VIEW":
                return handleViewEventMessage(requestMap);

            case "scancode_push":
                return handleScanCodePushEventMessage(requestMap);

            case "scancode_waitmsg":
                return handleScanCodeWaitmsgEventMessage(requestMap);

            case "pic_sysphoto":
                return handleSysPhotoEventMessage(requestMap);

            case "pic_photo_or_album":
                return handlePicPhotoOrAlbumEventMessage(requestMap);

            case "pic_weixin":
                return handlePicWeixinEventMessage(requestMap);

            case "location_select":
                return handleLocationSelectEventMessage(requestMap);

            case "view_miniprogram":
                return handleViewMiniProgramEventMessage(requestMap);
            //endregion

            //region 接收普通事件推送
            case "subscribe":
            case "unsubscribe":
                return handlerSubscribeAndUnsubscribeEventMessage(requestMap);
                
            case "SCAN":
                return handlerScanEventMessage(requestMap);

            case "LOCATION":
                return handlerLocationEventMessage(requestMap);
            //endregion

            case "TEMPLATESENDJOBFINISH"://在模版消息发送任务完成后，微信服务器会将是否送达成功作为通知，发送到开发者中心中填写的服务器配置地址中。
                return handlerTemplateSendJobFinishEventMessage(requestMap);
        }
        
        return null;
    }

    /**
     * 在模版消息发送任务完成后，微信服务器会将是否送达成功作为通知，发送到开发者中心中填写的服务器配置地址中。
     * <xml>
     *   <ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>
     *   <FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]></FromUserName>
     *   <CreateTime>1395658920</CreateTime>
     *   <MsgType><![CDATA[event]]></MsgType>
     *   <Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>
     *   <MsgID>200163836</MsgID>
     *   <Status><![CDATA[success]]></Status>
     * </xml>
     * 参数	说明
     * ToUserName	公众号微信号
     * FromUserName	接收模板消息的用户的openid
     * CreateTime	创建时间
     * MsgType	消息类型是事件
     * Event	事件为模板消息发送结束
     * MsgID	消息id
     * Status	发送状态为成功
     *
     * Status:
     * success 发送状态为成功(1、送达成功时)
     * failed:user block 发送状态为用户拒绝接收(2、送达由于用户拒收（用户设置拒绝接收公众号消息）而失败时)
     * failed: system failed 发送状态为发送失败（非用户拒绝）(3、送达由于其他原因失败时)
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handlerTemplateSendJobFinishEventMessage(Map<String, Object> requestMap) {
        String msgID = requestMap.get("MsgID").toString();
        String status = requestMap.get("Status").toString();
        String msg = String.format("模板消息[%s]发送状态：【%s】",msgID,status);
        System.out.println(msg);
        return null;
    }

    /**
     * 上报地理位置事件
     * 用户同意上报地理位置后，每次进入公众号会话时，都会在进入时上报地理位置，
     * 或在进入会话后每5秒上报一次地理位置，公众号可以在公众平台网站中修改以上设置。
     * 上报地理位置时，微信会将上报地理位置事件推送到开发者填写的URL。
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>123456789</CreateTime>
     *   <MsgType><![CDATA[event]]></MsgType>
     *   <Event><![CDATA[LOCATION]]></Event>
     *   <Latitude>23.137466</Latitude>
     *   <Longitude>113.352425</Longitude>
     *   <Precision>119.385040</Precision>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，LOCATION
     * Latitude	地理位置纬度
     * Longitude	地理位置经度
     * Precision	地理位置精度
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handlerLocationEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * 扫描带参数二维码事件
     * 用户扫描带场景值二维码时，可能推送以下两种事件：
     * 1、如果用户还未关注公众号，则用户可以关注公众号，关注后微信会将带场景值关注事件推送给开发者。
     * 2、如果用户已经关注公众号，则微信会将带场景值扫描事件推送给开发者。
     *
     * 1. 用户未关注时，进行关注后的事件推送
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[FromUser]]></FromUserName>
     *   <CreateTime>123456789</CreateTime>
     *   <MsgType><![CDATA[event]]></MsgType>
     *   <Event><![CDATA[subscribe]]></Event>
     *   <EventKey><![CDATA[qrscene_123123]]></EventKey>
     *   <Ticket><![CDATA[TICKET]]></Ticket>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，subscribe
     * EventKey	事件KEY值，qrscene_为前缀，后面为二维码的参数值
     * Ticket	二维码的ticket，可用来换取二维码图片
     *
     * 2. 用户已关注时的事件推送
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[FromUser]]></FromUserName>
     *   <CreateTime>123456789</CreateTime>
     *   <MsgType><![CDATA[event]]></MsgType>
     *   <Event><![CDATA[SCAN]]></Event>
     *   <EventKey><![CDATA[SCENE_VALUE]]></EventKey>
     *   <Ticket><![CDATA[TICKET]]></Ticket>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，SCAN
     * EventKey	事件KEY值，是一个32位无符号整数，即创建二维码时的二维码scene_id
     * Ticket	二维码的ticket，可用来换取二维码图片
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handlerScanEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * 关注/取消关注事件
     * 用户在关注与取消关注公众号时，微信会把这个事件推送到开发者填写的URL。
     * 方便开发者给用户下发欢迎消息或者做帐号的解绑。
     * 为保护用户数据隐私，开发者收到用户取消关注事件时需要删除该用户的所有信息。
     *
     * 微信服务器在五秒内收不到响应会断掉连接，并且重新发起请求，总共重试三次。
     * 关于重试的消息排重，推荐使用FromUserName + CreateTime 排重。
     * 假如服务器无法保证在五秒内处理并回复，可以直接回复空串，微信服务器不会对此作任何处理，并且不会发起重试。
     *
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[FromUser]]></FromUserName>
     *   <CreateTime>123456789</CreateTime>
     *   <MsgType><![CDATA[event]]></MsgType>
     *   <Event><![CDATA[subscribe]]></Event>
     * </xml>
     * 参数	描述
     * ToUserName	开发者微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，subscribe(订阅)、unsubscribe(取消订阅)
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handlerSubscribeAndUnsubscribeEventMessage(Map<String, Object> requestMap) {
        String event = requestMap.get("Event").toString();
        if("subscribe".equals(event)){
            String eventKey = requestMap.get("EventKey").toString();
            if(StringUtils.isNotBlank(eventKey)){
                System.out.println("EventKey: "+eventKey+",Ticket: "+requestMap.get("Ticket"));
                return null;
            }
            return new WxTextMessage(requestMap,"欢迎关注特惠充值中心，\r\n<a href=\"https://m.baidu.com\">点击进入充值</a>");
        }
        return null;
    }

    /**
     * 点击菜单跳转小程序的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[toUser]]></ToUserName>
     * 	<FromUserName><![CDATA[FromUser]]></FromUserName>
     * 	<CreateTime>123456789</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[view_miniprogram]]></Event>
     * 	<EventKey><![CDATA[pages/index/index]]></EventKey>
     * 	<MenuId>MENUID</MenuId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，view_miniprogram
     * EventKey	事件KEY值，跳转的小程序路径
     * MenuID	菜单ID，如果是个性化菜单，则可以通过这个字段，知道是哪个规则的菜单被点击了
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleViewMiniProgramEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * location_select：弹出地理位置选择器的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
     * 	<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
     * 	<CreateTime>1408091189</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[location_select]]></Event>
     * 	<EventKey><![CDATA[6]]></EventKey>
     * 	<SendLocationInfo>
     * 		<Location_X><![CDATA[23]]></Location_X>
     * 		<Location_Y><![CDATA[113]]></Location_Y>
     * 		<Scale><![CDATA[15]]></Scale>
     * 		<Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>
     * 		<Poiname><![CDATA[]]></Poiname>
     * 	</SendLocationInfo>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，location_select
     * EventKey	事件KEY值，由开发者在创建菜单时设定
     * SendLocationInfo	发送的位置信息
     * Location_X	X坐标信息
     * Location_Y	Y坐标信息
     * Scale	精度，可理解为精度或者比例尺、越精细的话 scale越高
     * Label	地理位置的字符串信息
     * Poiname	朋友圈POI的名字，可能为空
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleLocationSelectEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * pic_weixin：弹出微信相册发图器的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
     * 	<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
     * 	<CreateTime>1408090816</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[pic_weixin]]></Event>
     * 	<EventKey><![CDATA[6]]></EventKey>
     * 	<SendPicsInfo>
     * 		<Count>1</Count>
     * 		<PicList>
     * 			<item>
     * 				<PicMd5Sum><![CDATA[5a75aaca956d97be686719218f275c6b]]></PicMd5Sum>
     * 			</item>
     * 		</PicList>
     * 	</SendPicsInfo>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，pic_weixin
     * EventKey	事件KEY值，由开发者在创建菜单时设定
     * SendPicsInfo	发送的图片信息
     * Count	发送的图片数量
     * PicList	图片列表
     * PicMd5Sum	图片的MD5值，开发者若需要，可用于验证接收到图片
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handlePicWeixinEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * pic_photo_or_album：弹出拍照或者相册发图的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
     * 	<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
     * 	<CreateTime>1408090816</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[pic_photo_or_album]]></Event>
     * 	<EventKey><![CDATA[6]]></EventKey>
     * 	<SendPicsInfo>
     * 		<Count>1</Count>
     * 		<PicList>
     * 			<item>
     * 				<PicMd5Sum><![CDATA[5a75aaca956d97be686719218f275c6b]]></PicMd5Sum>
     * 			</item>
     * 		</PicList>
     * 	</SendPicsInfo>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，pic_photo_or_album
     * EventKey	事件KEY值，由开发者在创建菜单时设定
     * SendPicsInfo	发送的图片信息
     * Count	发送的图片数量
     * PicList	图片列表
     * PicMd5Sum	图片的MD5值，开发者若需要，可用于验证接收到图片
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handlePicPhotoOrAlbumEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * pic_sysphoto：弹出系统拍照发图的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
     * 	<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
     * 	<CreateTime>1408090651</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[pic_sysphoto]]></Event>
     * 	<EventKey><![CDATA[6]]></EventKey>
     * 	<SendPicsInfo>
     * 		<Count>1</Count>
     * 		<PicList>
     * 			<item>
     * 				<PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>
     * 			</item>
     * 		</PicList>
     * 	</SendPicsInfo>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，pic_sysphoto
     * EventKey	事件KEY值，由开发者在创建菜单时设定
     * SendPicsInfo	发送的图片信息
     * Count	发送的图片数量
     * PicList	图片列表
     * PicMd5Sum	图片的MD5值，开发者若需要，可用于验证接收到图片
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleSysPhotoEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * scancode_waitmsg：扫码推事件且弹出“消息接收中”提示框的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
     * 	<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
     * 	<CreateTime>1408090606</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[scancode_waitmsg]]></Event>
     * 	<EventKey><![CDATA[6]]></EventKey>
     * 	<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
     * 	<ScanResult><![CDATA[2]]></ScanResult>
     * 	</ScanCodeInfo>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，scancode_waitmsg
     * EventKey	事件KEY值，由开发者在创建菜单时设定
     * ScanCodeInfo	扫描信息
     * ScanType	扫描类型，一般是qrcode
     * ScanResult	扫描结果，即二维码对应的字符串信息
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleScanCodeWaitmsgEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * scancode_push：扫码推事件的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
     * 	<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
     * 	<CreateTime>1408090502</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[scancode_push]]></Event>
     * 	<EventKey><![CDATA[6]]></EventKey>
     * 	<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
     * 	<ScanResult><![CDATA[1]]></ScanResult>
     * 	</ScanCodeInfo>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间（整型）
     * MsgType	消息类型，event
     * Event	事件类型，scancode_push
     * EventKey	事件KEY值，由开发者在创建菜单时设定
     * ScanCodeInfo	扫描信息
     * ScanType	扫描类型，一般是qrcode
     * ScanResult	扫描结果，即二维码对应的字符串信息
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleScanCodePushEventMessage(Map<String, Object> requestMap) {
        return null;
    }

    /**
     * 点击菜单跳转链接时的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[toUser]]></ToUserName>
     * 	<FromUserName><![CDATA[FromUser]]></FromUserName>
     * 	<CreateTime>123456789</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[VIEW]]></Event>
     * 	<EventKey><![CDATA[www.qq.com]]></EventKey>
     * 	<MenuId>MENUID</MenuId>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，VIEW
     * EventKey	事件KEY值，设置的跳转URL
     * MenuID	指菜单ID，如果是个性化菜单，则可以通过这个字段，知道是哪个规则的菜单被点击了。
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleViewEventMessage(Map<String, Object> requestMap) {
        String eventKey = requestMap.get("EventKey").toString();
        System.out.println("handleViewEventMessage: "+eventKey);
        return null;
    }

    /**
     * 点击菜单拉取消息时的事件推送
     * <xml>
     * 	<ToUserName><![CDATA[toUser]]></ToUserName>
     * 	<FromUserName><![CDATA[FromUser]]></FromUserName>
     * 	<CreateTime>123456789</CreateTime>
     * 	<MsgType><![CDATA[event]]></MsgType>
     * 	<Event><![CDATA[CLICK]]></Event>
     * 	<EventKey><![CDATA[EVENTKEY]]></EventKey>
     * </xml>
     * 参数	描述
     * ToUserName	开发者 微信号
     * FromUserName	发送方帐号（一个OpenID）
     * CreateTime	消息创建时间 （整型）
     * MsgType	消息类型，event
     * Event	事件类型，CLICK
     * EventKey	事件KEY值，与自定义菜单接口中KEY值对应
     * @param requestMap
     * @return
     */
    private static WxBaseMessage handleClickEventMessage(Map<String, Object> requestMap) {
        return new WxTextMessage(requestMap,"你点了我！"+requestMap.get("EventKey"));
    }
    //endregion
}
